package com.bankcard.bininfo.trie;

import java.util.concurrent.locks.StampedLock;

public class MemoryTrieStorage implements TrieStorage {
    private volatile TrieNode root = new TrieNode();
    private final StampedLock trieLock = new StampedLock();

    @Override
    public void insertIntoTrie(String bin) {
        long stamp = trieLock.writeLock();
        try {
            TrieNode current = root;
            for (char c : bin.toCharArray()) {
                int index = c - '0';
                if (current.children[index] == null) {
                    current.children[index] = new TrieNode();
                }
                current = current.children[index];
            }
            current.isEndOfBin = true;
        } finally {
            trieLock.unlockWrite(stamp);
        }
    }

    @Override
    public String findLongestMatch(String accountNumber) {
        long stamp = trieLock.tryOptimisticRead();
        String result = findLongestMatchInternal(accountNumber);
        if (!trieLock.validate(stamp)) {
            stamp = trieLock.readLock();
            try {
                result = findLongestMatchInternal(accountNumber);
            } finally {
                trieLock.unlockRead(stamp);
            }
        }
        return result;
    }

    private String findLongestMatchInternal(String accountNumber) {
        TrieNode current = root;
        StringBuilder matchedBin = new StringBuilder();
        for (char c : accountNumber.toCharArray()) {
            int index = c - '0';
            if (current.children[index] == null) {
                break;
            }
            current = current.children[index];
            matchedBin.append(c);
            if (current.isEndOfBin) {
                return matchedBin.toString();
            }
        }
        return null;
    }

    private static class TrieNode {
        TrieNode[] children = new TrieNode[10];  // 0-9 digits
        boolean isEndOfBin;
    }
}